package com.atguigu.gulimall.ware.config;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.to.mq.MqMessage;
import com.atguigu.gulimall.ware.service.MqMessageService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.Date;
import java.util.Map;

/**
 * MQ 的回调函数
 */
@Configuration
public class MyRabbitConfig {

//    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    MqMessageService mqMessageService;


    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        initRabbitTemplate();
        return rabbitTemplate;
    }


    // 把消息使用json序列化的方式
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }


    /**
     * 定制 RabbitTemplate
     * 1、服务器收到消息
     *      1、spring.rabbitmq.publisher-confirms=true
     *      2、设置确认回调 setConfirmCallback
     * 2、 消息正确抵达队列 回调
     *      1、## 开启发送端消息抵达队列的确认
     *          spring.rabbitmq.publisher-returns=true
     *      2、## 只要抵达队列 优先异步回调
     *          spring.rabbitmq.template.mandatory=true
     * 3、消费端
     *      1、##手动ACK确认
     *          spring.rabbitmq.listener.simple.acknowledge-mode=manual
     */
    public void initRabbitTemplate() {

        /**
         * ACK 确认机制
         * @param correlationData correlation data for the callback.
         * @param ack true for ack, false for nack
         * @param cause An optional cause, for nack, when available, otherwise null.
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause)->{
            System.out.println("==============库存 ：成功发送消息到服务器回调==========" );
            System.out.println( "correlationData:" + correlationData + ",ack:" + ack + ",cause:" + cause);
            if (ack) {
                // 消息已成功发送到Broker并得到确认
                System.out.println("消息发送成功");
                String id = correlationData.getId();
                MqMessage mqMessage = new MqMessage();
                mqMessage.setMessageId(id);
                mqMessage.setMessageStatus(1);  // 发送成功
                mqMessage.setUpdateTime(new Date());
                mqMessageService.updateById(mqMessage);

                // 在这里执行相应的逻辑
            } else {
                // 消息发送失败或未得到确认
                System.out.println("消息发送失败：" + cause);
                // 在这里执行相应的逻辑
            }
        });

        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {

            /**
             //             * 只要消息没投递到指定的队列，就触发失败回调
             //             * @param message the returned message.
             //             * @param i the reply code.
             //             * @param s the reply text.
             //             * @param s1 the exchange.
             //             * @param s2 the routing key.
             //             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {

                System.out.println("=============交换机发送消息到消息队列失败回调==========");
                System.out.println("message===>" + message + "replyCode===>" + replyCode + "replyText==>" + replyText + "exchange==>" + exchange + "routingKey==>" + routingKey);
                System.out.println("消息为正确抵达队列。。。");
                String string = new String(message.getBody());
                Map<String,String> orderEntity = JSON.parseObject(string, Map.class);
                MqMessage mqMessage = new MqMessage();
                mqMessage.setMessageId(orderEntity.get("mqMessageId"));
                mqMessage.setMessageStatus(2);  // 错误抵达
                mqMessage.setUpdateTime(new Date());
                mqMessageService.updateById(mqMessage);
            }
        });
    }

}
